package borge.web.teamspirit.server;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;

import javax.jdo.JDOException;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import borge.web.teamspirit.client.data.Association;
import borge.web.teamspirit.client.data.Comment;
import borge.web.teamspirit.client.data.League;
import borge.web.teamspirit.client.data.LeagueDivision;
import borge.web.teamspirit.client.data.Match;
import borge.web.teamspirit.client.data.MatchAttendance;
import borge.web.teamspirit.client.data.MatchPlayerStats;
import borge.web.teamspirit.client.data.News;
import borge.web.teamspirit.client.data.Person;
import borge.web.teamspirit.client.data.Serie;
import borge.web.teamspirit.client.data.Sport;
import borge.web.teamspirit.client.data.Team;
import borge.web.teamspirit.client.data.TeamPlayer;
import borge.web.teamspirit.client.data.TeamSerieInfo;
import borge.web.teamspirit.client.data.League.Category;
import borge.web.teamspirit.client.interfaces.PersistentData;
import borge.web.teamspirit.client.servercomm.DBQuery;
import borge.web.teamspirit.client.servercomm.DBQueryResults;
import borge.web.teamspirit.client.servercomm.DBQueryResults.Result;

public class DatabaseHandler {

	public <T extends PersistentData> DBQueryResults saveObject(T aObject) {

		System.out.println("saveObject");

		PersistenceManager pm = PMF.get().getPersistenceManager();

		DBQueryResults result;
		try {
			pm.makePersistent(aObject);
			result = new DBQueryResults(true, null);
		} catch (JDOException e) {
			e.printStackTrace();
			result = new DBQueryResults(false, e.toString());
		} catch (Exception e) {
			e.printStackTrace();
			result = new DBQueryResults(false, e.toString());
		} finally {
			pm.close();
		}

		System.out.println("returning");
		return result;
	}

	private boolean valueSet(String aValue) {
		if (aValue != null && aValue.length() > 0)
			return true;

		return false;
	}

	public PersistentData getObject(DBQuery aQuery) {
		Result result = getObjectList(aQuery);
		if (result.getResultList().size() == 0)
			return null;

		return result.getResultList().get(0);
	}

	@SuppressWarnings("unchecked")
	public Result getObjectList(
			DBQuery aQuery) {

		System.out.println("getObjectList");

		PersistenceManager pm = PMF.get().getPersistenceManager();

		String strQuery = aQuery.getQuery();
		System.out.println("query = " + strQuery);
		Query query = pm.newQuery(strQuery);

		

		Result result = null;
		try {
			List<PersistentData> results;
			if(aQuery.getParamValues() != null)
				results = (List<PersistentData>)query.executeWithArray(aQuery.getParamValues().toArray());
			else
				results = (List<PersistentData>) query.execute();

			
			System.out.println("result size = " + results.size());
			// TODO: must fix this!!!
			List<PersistentData> newList = (List<PersistentData>) pm.detachCopyAll(results);//new ArrayList<T>();
			/*for (T t : results) {
				System.out.println("re-adding object");
				newList.add(t);
			}*/
			result = new Result(newList);
		} 
		catch (JDOException e) {
			e.printStackTrace();
			result = new Result(e.toString());
		}
		catch(Exception e){
			e.printStackTrace();
		}
		finally {
			query.closeAll();
			pm.close();
		}
		System.out.println("returning..");
		return result;

	}
	

	public <T extends PersistentData> DBQueryResults deleteObject(
			Class<T> aClass, Object aKey) {

		PersistenceManager pm = PMF.get().getPersistenceManager();
		DBQueryResults result;
		try {

			pm.deletePersistent(pm.getObjectById(aClass, aKey));
			result = new DBQueryResults(true, null);
		} catch (JDOException e) {
			e.printStackTrace();
			result = new DBQueryResults(false, e.toString());
		} finally {
			pm.close();
		}

		return result;

	}
	
	public <T extends PersistentData> DBQueryResults deleteObject(DBQuery aQuery) {
		// TODO Auto-generated method stub

		System.out.println("deleteObject by query");
		PersistenceManager pm = PMF.get().getPersistenceManager();
		DBQueryResults result;
		try{
			String strQuery = aQuery.getQuery();
			Query query = pm.newQuery(strQuery);

			System.out.println("query = " + strQuery);
			query.deletePersistentAll();

		}
		catch(Exception e){
			e.printStackTrace();
		}
		finally{
			
		}
		
		return null;
	}

	public void testCreateEntities() {

		System.out.println("testCreateEntities");

		// create a full system with stuff..and stuff..
		// create x persons
		// create x associations
		// create x teams
		// create x team players for each team
		// create x leagues for an association, with divisions
		// join x teams to an association league division
		// create x independent series in a team
		// create x matches to the serie
		
		String[] names = {"Andreas Borglin", "KJ Olsson", "Axel Bengtsson", "Patrik Sandberg", "Andreas Carlsson", "Jonas Anehamre",
				"Joel Sannerstedt", "Ola Olsson", "Fredrik Linander"};
		String[] associations = {"FreeMode", "LUGI", "KG Korpen"};
		boolean[] assModes = {true, false, false};
		
		
		String[] teams = {"Bengts Bolltroll", "Flugorna", "Aporna", "Korna", "The naked pigs", "KungPowChickens", "MonkeyAsses",
				"SnowBalls", "FurryFruits"};
		String[] sports = {"Fotboll", "Hockey", "Volleyboll"};
		
		PersistenceManager pm = PMF.get().getPersistenceManager();
		
		try{
			
			// delete all
			Query pq = pm.newQuery(Person.class);
			pq.deletePersistentAll();
			
			Query tg = pm.newQuery(Team.class);
			tg.deletePersistentAll();
			
			Query aq = pm.newQuery(Association.class);
			aq.deletePersistentAll();
			
			Query sq = pm.newQuery(Sport.class);
			sq.deletePersistentAll();
			
			Query lq = pm.newQuery(League.class);
			lq.deletePersistentAll();
			
			Query serq = pm.newQuery(Serie.class);
			serq.deletePersistentAll();
			
			Query tsi = pm.newQuery(TeamSerieInfo.class);
			tsi.deletePersistentAll();
			
			Query com = pm.newQuery(Comment.class);
			com.deletePersistentAll();
			
			Query news = pm.newQuery(News.class);
			news.deletePersistentAll();
			
			Query mps = pm.newQuery(MatchPlayerStats.class);
			mps.deletePersistentAll();
			
			Query ma = pm.newQuery(MatchAttendance.class);
			ma.deletePersistentAll();
//			if(true){
//				System.out.println("returning");
//				return;
//			}
			
			List<Person> personsList = new ArrayList<Person>();
			List<Team> teamsList = new ArrayList<Team>();
			List<Association> associationsList = new ArrayList<Association>();
			List<Sport> sportsList = new ArrayList<Sport>();
			List<League> leaguesList = new ArrayList<League>();
			List<LeagueDivision> leagueDivsList = new ArrayList<LeagueDivision>();
			List<Serie> seriesList = new ArrayList<Serie>();
			
			
			for(int i = 0; i < names.length; ++i){
				
				Person p = createTestPerson(names[i]);
				Person saved = pm.makePersistent(p);
				personsList.add(saved);
			}
			
			for(int i = 0; i < sports.length; ++i){
				
				Sport s = createTestSport(sports[i]);
				Sport saved = pm.makePersistent(s);
				sportsList.add(saved);
			}
			
			for(int i = 0; i < associations.length; ++i){
				Person p = personsList.get(i);
				Association ass = createTestAssociation(associations[i], p.getEncodedKey(), assModes[i]);
				Association saved = pm.makePersistent(ass);
				associationsList.add(saved);
				
				p.addAssociationName(ass.toString());
				pm.makePersistent(p);
		
				League[] leagues = {new League("HT09", Category.MEN), new League("HT09", Category.WOMEN), 
						new League("VT10", Category.MEN), new League("VT10", Category.MIXED)};
				
				for(League league : leagues){
					league.setAssociationKey(saved.getEncodedKey());
					league.iAssociationName = saved.toString();
					Random rand = new Random();
					int sport = rand.nextInt(sportsList.size());
					league.setSportKey(sportsList.get(sport).getEncodedKey());
					league.iSportName = sportsList.get(sport).getName();
					League savedl = pm.makePersistent(league);
					leaguesList.add(savedl);
					
		
					LeagueDivision[] divisions = {new LeagueDivision("1", "a"), new LeagueDivision("1", "b"), 
							new LeagueDivision("2", "a"), new LeagueDivision("2", "c")};
					for(LeagueDivision ld : divisions){
						
						ld.setLeagueKey(savedl.getEncodedKey());
						savedl.addDivision(ld);
						
					}
					
					pm.makePersistent(savedl);
					
				}
			}
			
			for(int i = 0; i < teams.length; ++i){
				Person pers = personsList.get(i);
				Team t = createTestTeam(teams[i], pers.getEncodedKey());
				Team saved = pm.makePersistent(t);
				teamsList.add(saved);
				
				pers.addOwnedTeam(saved.getName());
				pm.makePersistent(pers);
				
				// add news
				for(int j = 0; j < 5; ++j){
					
					News newss = new News();
					newss.setDate(new Date());
					newss.setPersonKey(pers.getEncodedKey());
					newss.setPosterName(pers.toString());
					newss.setTitle("News: " + j);
					newss.setText("New news for everyone!");
					newss.setParentKey(saved.getEncodedKey());
					pm.makePersistent(newss);
				}
				
				List<TeamPlayer> players = new ArrayList<TeamPlayer>();
				// add players to team
				int j = 0;
				for(Person p : personsList){
					String personKey = p.getEncodedKey();
					TeamPlayer player = createTestPlayer(saved.getEncodedKey(), personKey, p.toString());
					TeamPlayer sp = pm.makePersistent(player);
					players.add(sp);
					
					p.addTeamName(saved.getName());
					pm.makePersistent(p);
					
					j++;
				}
				
				// add series to team
				for(League league : leaguesList){
					
					//League league = (League)pm.getObjectById(lgKey);
					Serie serie = createTestSerie();
					serie.setTeamKey(saved.getEncodedKey());
					Random rand = new Random();
					int div = rand.nextInt(league.getNumDivisions());
					LeagueDivision division = league.getDivision(div);
					serie.setLeagueDivisionKey(division.getEncodedKey());
					
					Serie savedSerie = pm.makePersistent(serie);
					
					// add matches to serie
					for(String tname : teams){
						
						Match match = createTestMatch(tname);
						match.setOwningSerieKey(savedSerie.getEncodedKey());
						Match savedMatch = pm.makePersistent(match);
						
						// a comment
						Comment comment = new Comment();
						comment.setParentKey(savedMatch.getEncodedKey());
						comment.setDate(new Date());
						comment.setPoster(players.get(0).toString(), players.get(0).getEncodedKey());
						comment.setText("Testing by");
						Comment savedc = pm.makePersistent(comment);
						
						// attendance
						for(TeamPlayer player : players){
							
							rand = new Random();
							int val = rand.nextInt(3);
							// 0 = no answer = no entity, 1 = yes, 2 = n0
							if(val != 0){
							
								MatchAttendance mat = new MatchAttendance();
								mat.setMatchKey(savedMatch.getEncodedKey());
								mat.setPlayerKey(player.getEncodedKey());
								
								if(val == 1)
									mat.setAttending(true);
								else 
									mat.setAttending(false);
								
								pm.makePersistent(mat);
							}
							
							
						}
						
						for(int k = 0;k < 5; k++){
							MatchPlayerStats stats = new MatchPlayerStats();
							stats.setPlayerKey(players.get(k).getEncodedKey());
							stats.setMatchKey(savedMatch.getEncodedKey());
							stats.setGoals(k);
							stats.setAssists(k+1);
							stats.setRedCard(true);
							stats.setYellowCard(true);
							pm.makePersistent(stats);
							//match.addPlayerStats(stats);
						}
						
						//savedSerie.addMatch(match);
						//System.out.println("match stats = " + sm.getPlayerStats().size());
						
					}
					
					//pm.makePersistent(savedSerie);
			
					// add comments
					for(Person p : personsList){
						
						Comment comment = new Comment();
						comment.setParentKey(savedSerie.getEncodedKey());
						comment.setDate(new Date());
						comment.setPoster(p.toString(), p.getEncodedKey());
						comment.setText("Testing by " + p.toString());
						Comment savedc = pm.makePersistent(comment);
						//System.out.println("comment saved with id = " + savedc.getEncodedKey());
						
					}
					
					// update team with serie info
					saved.addSerie(savedSerie.getEncodedKey(), league.iAssociationName, league.iSportName, 
							league.getSeason(), division.toString());
					//System.out.println("saving team with serie info");
					//Team saved2 = pm.makePersistent(saved);
					//System.out.println("serie size = " + saved2.getSeries().size());
					
				}
				
				pm.makePersistent(saved);
				//System.out.println("fetched st size = " + saved2.getSeries().size());
			}
			
			pm.close();
			
			
		}
		catch(Exception e){
			e.printStackTrace();
		}
		
		System.out.println("creating done");

	}

	public void testPrintEntities() {

		System.out.println("testPrintEntities");

		PersistenceManager pm = PMF.get().getPersistenceManager();

		try{
		
			/*
			Query pq = pm.newQuery(Test.class);
			
			pq.deletePersistentAll();
			
			Test test = new Test();
			test.addSomeInnerTests();
			
			Test saved = pm.makePersistent(test);
			System.out.println("persisted Test innerTests size = " + saved.getInnerTests().size());
			System.out.println("Saved Test key = " + saved.getKey());*/
			
			
			Query query = pm.newQuery("select from borge.web.teamspirit.client.data.Comment");
			List<Comment> lis = (List<Comment>)query.execute();
			System.out.println("size = " + lis.size());
			/*
			for(Team t : lis){
				List<SerieTracker> st = t.getSeries();
				
				System.out.println("st size = " + st.size());
				if(st.size() > 0)
					System.out.println("first ass name = " + st.get(0).getAssociationName());
				
				List<String> test = t.getTest();
				System.out.println("test size = " + test.size());
			}
			*/
		}
		catch(Exception e){
			e.printStackTrace();
		}
		finally{
			pm.close();
		}
		
		
		/*
		try{
			pm = PMF.get().getPersistenceManager();
		
			Query query = pm.newQuery(Team.class);
			List<Team> list = (List<Team>)query.execute();
			System.out.println("Teams = " + list.size());
			
		
			for(Team team : list){
				List<TeamSerieInfo> series = team.getSeries();
				System.out.println("series = " + series.size());
			}
			
		}
		catch(Exception e){
			e.printStackTrace();
		}
		finally{
			pm.close();
		}*/
	}

	
	private News createTestNews() {
		News news = new News();
		news.setDate(new Date());
		news.setText("This is news");
		news.setTitle("Test news");
		return news;
	}
	
	private TeamPlayer createTestPlayer(String teamKey, String personKey, String personName){
		TeamPlayer player = new TeamPlayer();
		player.setTeamKey(teamKey);
		player.setPersonKey(personKey);
		player.setPersonName(personName);
		return player;
	}

	private Team createTestTeam(String name, String ownerKey) {

		Team team = new Team();
		team.setName(name);
		team.setOwner(ownerKey);
		return team;

	}

	private Person createTestPerson(String name) {
		Person person = new Person();
		//person.setFirstName(fname);
		//person.setLastName(lname);
		person.setName(name);
		person.setBirthDay(new Date());
		String dotname = name.replace(' ', '.');
		person.setEmail(dotname + "@gmail.com");
		person.setPassword("apa");
		person.setNickName("Whatever");
		person.setPhone("0702850531");
		return person;
	}
	
	private Association createTestAssociation(String name, String adminKey, boolean mode){
		
		Association ass = new Association();
		ass.setName(name);
		ass.setAdminPerson(adminKey);
		ass.setMode(mode);
		return ass;
	}
	
	private Sport createTestSport(String name){
		Sport sport = new Sport();
		sport.setName(name);
		return sport;
	}
	
	private League createTestLeague(String assKey, String sportKey, String season, Category category){

		League league = new League();
		league.setAssociationKey(assKey);
		league.setSportKey(sportKey);
		league.setSeason(season);
		league.setCategory(category);
		
		return league;
	}
	
	private LeagueDivision createTestDivision(String leagueKey, String sdiv, String subdiv){
		LeagueDivision div = new LeagueDivision();
		div.setLeagueKey(leagueKey);
		div.setDivision(sdiv);
		div.setSubDivision(subdiv);
		return div;
	}
	
	private Serie createTestSerie(){
		Serie serie = new Serie();
		
		return serie;
	}

	private Match createTestMatch(String opponents){
		Match match = new Match();
		match.setOpponents(opponents);
		Random rand = new Random();
		match.setOurScore(rand.nextInt(10));
		match.setOpponentScore(rand.nextInt(10));
		match.setCity("Lund");
		match.setDateTime(new Date());
		match.setField("H2");
		match.setGatheringTime(new Date());
		match.setPeriods(2);
		match.setPeriodLengthInMinutes(60);
		match.setStadium("Victoria");
		return match;
	}

}
